﻿using GeebaClient;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using ServerAdapter.WcfGeebaService;
using ServerAdapter.Utils;
using WcfGeebaServer.DBDAL;

namespace AcceptnaceTests
{
    
    
    /// <summary>
    ///This is a test class for ConsoleClientTest and is intended
    ///to contain all ConsoleClientTest Unit Tests
    ///</summary>
    [TestClass()]
    public class ConsoleClientTest
    {

        private static ConsoleClient_Accessor _target = new ConsoleClient_Accessor();
        private static Member _admin = null;

        private TestContext testContextInstance;

        public ConsoleClientTest()
        {
            //target = new ConsoleClient_Accessor();
            Data.ClearDB();
            GPolicy policy = new GPolicy();
            _target.server.serverInit(TestUtils.GetAdminUsername(), TestUtils.GetAdminPassword(), policy);
            User adminUser = _target.server.serverEntry();
            _admin = _target.server.serverLogin(adminUser, TestUtils.GetAdminUsername(), TestUtils.GetAdminPassword());
        }

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        #region HelpMethods

        private static string AddNewSubForum()
        {
            string topic = TestUtils.GetNextTopic();
            _target.server.serverAddSubForum(_admin, topic, TestUtils.GetAdminUsername());
            return topic;
        }

        private static GThread PostNewThread(string topic, Member member)
        {
            GThread th = new GThread();
            th._subject = TestUtils.GetNextSubject();
            th._content = TestUtils.GetNextContent();
            th._publisher = member;
            th._id = _target.server.serverPublish(member, topic, th);
            return th;
        }

        private static GPost PostNewComment(string topic, Member member, int thread_id)
        {
            GPost post = new GPost();
            post._subject = TestUtils.GetNextSubject();
            post._content = TestUtils.GetNextContent();
            post._publisher = member;
            post._id = _target.server.commentOnThread(member, post, topic, thread_id);
            return post;
        }

        private static Member LoginNewMember()
        {
            string username = TestUtils.GetNextUsername();
            _target.server.serverRegister(username, TestUtils.GetPassword());
            Member mem = _target.server.serverLogin(_target.server.serverEntry(), username, TestUtils.GetPassword());
            return mem;
        }
        
        #endregion

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void EntranceTest()
        {
            Assert.IsNotNull(_target.server.serverEntry());
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void RegistrationTest()
        {
            Assert.IsNotNull(_target.server.serverEntry());
            string username = TestUtils.GetNextUsername();
            string password = TestUtils.GetPassword();
            Assert.IsTrue(_target.server.serverRegister(username, password));
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void RegistrationFailureTest()
        {
            Assert.IsNotNull(_target.server.serverEntry());
            string username = TestUtils.GetNextUsername();
            string password = TestUtils.GetPassword();

            Assert.IsTrue(_target.server.serverRegister(username, password));
            Assert.IsFalse(_target.server.serverRegister(username, password));
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void LoginTest()
        {
            User olduser = _target.server.serverEntry();
            string username = TestUtils.GetNextUsername();
            string password = TestUtils.GetPassword();
            _target.server.serverRegister(username, password);
            Member actual = _target.server.serverLogin(olduser, username, password);
            Assert.IsNotNull(actual);
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void LogoutTest()
        {
            string username = TestUtils.GetNextUsername();
            string password = TestUtils.GetPassword();
            _target.server.serverRegister(username, password);
            Member member = _target.server.serverLogin(_target.server.serverEntry(), username, password);
            User actual = _target.server.serverLogout(member);
            Assert.AreEqual(UserType.Guest, actual.userType);
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void GetSubForumsTest()
        {
            List<GSubForum> sfs = _target.server.serverGetSubForums();
            Assert.IsNotNull(sfs);
            Assert.IsTrue(sfs.Count == 0);

            AddNewSubForum();
            sfs = _target.server.serverGetSubForums();
            Assert.IsNotNull(sfs);
            Assert.IsTrue(sfs.Count == 1);

            AddNewSubForum();
            sfs = _target.server.serverGetSubForums();
            Assert.IsNotNull(sfs);
            Assert.IsTrue(sfs.Count == 2);
        }


        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void GetThreadsTest()
        {
            string topic = AddNewSubForum();
            Member mem = LoginNewMember();
            GThread th = PostNewThread(topic, mem);
            _target.server.serverLogout(mem);

            // get threads
            GSubForum sf = new GSubForum();
            sf.topic = topic;
            List<GThread> actual = _target.server.serverGetThreads(sf);
            // verify threads
            Boolean res = false;
            for (int i = 0; i < actual.Count; i++)
            {
                if (actual[i]._id == th._id)
                {
                    res = true;
                    break;
                }
            }
            Assert.IsTrue(res);
        }

        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void PublishMessageTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            GThread newMessage = new GThread();
            newMessage._subject = TestUtils.GetNextSubject();
            newMessage._content = TestUtils.GetNextContent();
            newMessage._publisher = member;
            try
            {
                _target.server.serverPublish(member, topic, newMessage);
                Assert.IsTrue(true);
            }
            catch (Exception e)
            {
                Console.Write(e.Data);
                Assert.IsTrue(false);
            }
        }

        [TestMethod]
        [DeploymentItem("GeebaClient.exe")]
        public void CommentPostTest()
        {
            string topic = AddNewSubForum();
            GThread thread = PostNewThread(topic, _admin);
            Member member = LoginNewMember();

            GPost post = PostNewComment(topic, member, thread._id);
            Assert.IsTrue(post._id > 0);

            GPost post2 = PostNewComment(topic, member, post._id);
            Assert.IsTrue(post2._id > 0);

            try
            {
                PostNewComment(topic, (Member)_target.server.serverEntry(), post2._id);
                Assert.Fail("comment by user not member or logged in.");
            }
            catch
            {
                Assert.IsTrue(true);
            }
        }

        /// <summary>
        ///A test for serverAddSubForum
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void AddSubForumTest()
        {
            AddNewSubForum();
            AddNewSubForum();
            string topic = AddNewSubForum();
            AddNewSubForum();

            bool expected = true;
            bool actual = false;
            foreach (GSubForum sf in _target.server.serverGetSubForums())
            {
                if (sf.topic.Equals(topic))
                {
                    actual = true;
                    break;
                }
            }
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for serverAddModerator
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void AddModeratorTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            
            // should fail:
            Assert.IsFalse(_target.server.serverAddModerator(_admin, topic, member.username));
            
            // should work:
            for (int i = 0; i < 5; i++)
            {
                PostNewThread(topic, member);
            }
            bool expected = true;
            bool actual = _target.server.serverAddModerator(_admin, topic, member.username);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for serverGetMemberThreadCount
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void GetMemberThreadCountTest()
        {
            Member member = LoginNewMember();

            int before = _target.server.serverGetMemberThreadCount(_admin, member.username);

            string topic = AddNewSubForum();
            PostNewThread(topic, member);

            int after = _target.server.serverGetMemberThreadCount(_admin, member.username);
            Assert.IsTrue(after - before == 1);
        }

        /// <summary>
        ///A test for serverGetThreadCount
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void GetThreadCountTest()
        {
            string topic = AddNewSubForum();
            
            int before = _target.server.serverGetThreadCount(_admin, topic);
            Assert.AreEqual(0, before); 

            Member member = LoginNewMember();
            PostNewThread(topic, member);
            
            int after = _target.server.serverGetThreadCount(_admin, topic);
            Assert.IsTrue(after - before == 1);
        }

        /// <summary>
        ///A test for serverRemoveModerator
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void RemoveModeratorTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            for (int i = 0; i < 5; i++)
            {
                PostNewThread(topic, member);
            }
            Assert.IsTrue(_target.server.serverAddModerator(_admin, topic, member.username));
            Assert.IsTrue(_target.server.serverRemoveModerator(_admin, topic, _admin.username));
        }

        /// <summary>
        ///A test for serverRemoveSubForum
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void RemoveSubForumTest()
        {
            string topic = AddNewSubForum();
            Assert.IsTrue(_target.server.serverRemoveSubForum(_admin, topic));
            AddNewSubForum();
            topic = AddNewSubForum();
            Assert.IsTrue(_target.server.serverRemoveSubForum(_admin, topic));
            //try
            //{
            //    target.server.serverRemoveSubForum(_admin, topic);
            //    Assert.IsTrue(false);
            //}
            //catch (Exception e)
            //{
            //    Console.Write(e.Data);
            //    Assert.IsTrue(true);
            //}
        }

        /// <summary>
        ///A test for serverRemoveThread
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void RemoveThreadTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            GThread newThread = PostNewThread(topic, member);

            Assert.IsTrue(newThread._id > 0);
            Assert.IsTrue(_target.server.serverRemoveThread(member, topic, newThread._id));
            //Assert.IsFalse(target.server.serverRemoveThread(member, topic, newThread._id));
        }

        /// <summary>
        ///A test for serverReplaceModerator
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void ReplaceModeratorTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            for (int i = 0; i < 5; i++)
            {
                PostNewThread(topic, member);
            }

            Assert.IsTrue(_target.server.serverReplaceModerator(_admin, topic, TestUtils.GetAdminUsername(), member.username));
        }

        /// <summary>
        ///A test for serverReplaceModerator
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GeebaClient.exe")]
        public void ChangePasswordTest()
        {
            Member member = LoginNewMember();
            string newPass = TestUtils.GetNewPassword();
            Assert.IsTrue(_target.server.changePassword(member, TestUtils.GetPassword(), newPass));
            _target.server.serverLogout(member);

            Member oldMember = _target.server.serverLogin(_target.server.serverEntry(), member.username, TestUtils.GetPassword());
            Assert.IsNull(oldMember);
            Member newMember = _target.server.serverLogin(_target.server.serverEntry(), member.username, newPass);
            Assert.IsNotNull(newMember);
            Assert.IsNotNull(_target.server.serverLogout(newMember));
        }

        [TestMethod]
        [DeploymentItem("GeebaClient.exe")]
        public void EditContentTest()
        {
            string topic = AddNewSubForum();
            Member member = LoginNewMember();
            GThread thread = PostNewThread(topic, member);
            Assert.IsTrue(_target.server.serverEditContent(member, topic, thread._id, TestUtils.GetNextContent()));
        }

        [TestMethod]
        [DeploymentItem("GeebaClient.exe")]
        public void BumpThreadTest()
        {
            string topic = AddNewSubForum();
            GThread th1 = PostNewThread(topic, _admin);
            GThread th2 = PostNewThread(topic, _admin);

            Assert.IsTrue(_target.server.serverBumpThread(_admin, topic, th1._id));
            GSubForum sf = new GSubForum();
            sf.topic = topic;
            List<GThread> ths = _target.server.serverGetThreads(sf);
            GThread thBummped = ths.Find(delegate(GThread thTemp){
                return thTemp._id == th1._id;
            });
            GThread thNotBummped = ths.Find(delegate(GThread thTemp){
                return thTemp._id == th2._id;
            });
            Assert.IsTrue(thBummped._modifiedDate > thNotBummped._modifiedDate);
        }

        [TestMethod]
        public void AdminTryToChangeMessageContentTest()
        {
            Member member = LoginNewMember();
            string topic = AddNewSubForum();
            GThread thread = PostNewThread(topic, member);

            Assert.IsTrue(_target.server.serverEditContent(member, topic, thread._id, "new content by member"));
            Assert.IsFalse(_target.server.serverEditContent(_admin, topic, thread._id, "new content by admin"));
        }

        [TestMethod]
        public void ModeratorTryToChangeMessageContentTest()
        {
            Member member = LoginNewMember();
            Member moderator = LoginNewMember();

            string topic = TestUtils.GetNextTopic();
            _target.server.serverAddSubForum(_admin, topic, moderator.username);
            GThread thread = PostNewThread(topic, member);

            Assert.IsTrue(_target.server.serverEditContent(member, topic, thread._id, "new content by member"));
            Assert.IsFalse(_target.server.serverEditContent(moderator, topic, thread._id, "new content by moderator"));
        }

        [TestMethod]
        public void SearchForMessageByContent()
        {
            string content = "special content for test 12345";
            string topic1 = AddNewSubForum();

            GThread th1 = new GThread();
            th1._subject = TestUtils.GetNextSubject();
            th1._content = content;
            th1._publisher = _admin;
            th1._id = _target.server.serverPublish(_admin, topic1, th1);
            string topic2 = AddNewSubForum();
            GThread th2 = new GThread();
            th2._subject = TestUtils.GetNextSubject();
            th2._content = content;
            th2._publisher = _admin;
            th2._id = _target.server.serverPublish(_admin, topic2, th2);

            GThread[] results = _target.server.searchByContent(content);
            Assert.IsTrue((results[0]._id == th1._id) || (results[0]._id == th2._id));
            Assert.IsTrue((results[1]._id == th1._id) || (results[1]._id == th2._id));
            Assert.IsTrue(results.Length == 2);

            results = _target.server.searchByContent(content.Substring(10));
            Assert.IsTrue((results[0]._id == th1._id) || (results[0]._id == th2._id));
            Assert.IsTrue((results[1]._id == th1._id) || (results[1]._id == th2._id));
            Assert.IsTrue(results.Length == 2);
        }

        [TestMethod]
        public void SearchForMessageByPublisher()
        {
            Member member = LoginNewMember();
            string topic1 = AddNewSubForum();
            GThread thread1 = PostNewThread(topic1, member);
            string topic2 = AddNewSubForum();
            GThread thread2 = PostNewThread(topic2, member);
            GThread[] results = _target.server.searchByUser(member.username);
            Assert.IsTrue((results[0]._id == thread1._id) || (results[0]._id == thread2._id));
            Assert.IsTrue((results[1]._id == thread1._id) || (results[1]._id == thread2._id));
            Assert.IsTrue(results.Length == 2);
        }

        [TestMethod]
        public void ShowNumberOfConnectedUsers()
        {
            int numOfUsers = _target.server.getOnlineUserCount();
            Member member = LoginNewMember();
            Assert.IsTrue(_target.server.getOnlineUserCount() == numOfUsers + 1);
            _target.server.serverLogout(member);
            Assert.IsTrue(_target.server.getOnlineUserCount() == numOfUsers);
        }

    }
}
